///
/// @file FuncCallInstruction.cpp
/// @brief 函数调用指令
/// @author zenglj (zenglj@live.com)
/// @version 1.0
/// @date 2024-09-29
///
/// @copyright Copyright (c) 2024
///
/// @par 修改日志:
/// <table>
/// <tr><th>Date       <th>Version <th>Author  <th>Description
/// <tr><td>2024-09-29 <td>1.0     <td>zenglj  <td>新建
/// </table>
///
#include "FuncCallInstruction.h"
#include "Function.h"
#include "Common.h"
#include "Type.h"
#include <GlobalVariable.h>
#include <iostream>

/// @brief 含有参数的函数调用
/// @param srcVal 函数的实参Value
/// @param result 保存返回值的Value
FuncCallInstruction::FuncCallInstruction(Function * _func,
                                         Function * calledFunc,
                                         std::vector<Value *> & _srcVal,
                                         Type * _type)
    : Instruction(_func, IRInstOperator::IRINST_OP_FUNC_CALL, _type), calledFunction(calledFunc)
{
    name = calledFunc->getName();
    // 实参拷贝
    for (auto & val: _srcVal) {
        addOperand(val);
    }
}

/// @brief 转换成字符串显示
/// @param str 转换后的字符串
void FuncCallInstruction::toString(std::string & str)
{
    // 构造函数调用前缀
    std::string str_call;
    if (type->isVoidType()) {
        str_call = "call void " + calledFunction->getIRName() + "(";
    } else {
        str_call = getIRName() + " = call " + type->toString() + " " + calledFunction->getIRName() + "(";
    }

    std::string str_arg;
    str = ""; // 清空输出字符串

    // 保存有效参数的 <type, name> 对
    std::vector<std::pair<std::string, std::string>> realArgs;

    // 第一步：收集有效参数
    for (int32_t k = 0; k < getOperandsNum(); ++k) {
        Value * operand = getOperand(k);

        // 跳过空指针或自身引用
        if (!operand || operand == this) {
            continue;
        }

        std::string typeStr = operand->getType()->toString();
        // if(operand->getType()->isPointerType()){
        //     typeStr += "*";
        // }
        std::string argName;

        // 情况 1：函数调用指令，直接取 IR 名称
        Instruction * instOperand = dynamic_cast<Instruction *>(operand);
        if (instOperand && instOperand->getOp() == IRInstOperator::IRINST_OP_FUNC_CALL) {
            argName = operand->getIRName();
        }
        // 情况 2：变量，需要加载其值
        else if ((dynamic_cast<LocalVariable *>(operand) != nullptr ||
                 dynamic_cast<GlobalVariable *>(operand) != nullptr)) {
            RegVariable * tempVar = func->newTempVariable(operand->getType());
            argName = tempVar->getIRName();

            // 加载指令写入到主输出字符串中
            str += argName + " = load " + typeStr + ", " + typeStr + "* " + operand->getIRName() + "\n\t";
        } 
        // 情况 3：普通寄存器/常量
        else {
            argName = operand->getIRName();
        }

        realArgs.emplace_back(typeStr, argName);
    }

    // 第二步：构建参数字符串，确保正确加逗号
    for (size_t i = 0; i < realArgs.size(); ++i) {
        str_arg += realArgs[i].first + " " + realArgs[i].second;
        if (i < realArgs.size() - 1) {
            str_arg += ", ";
        }
    }

    // 拼接最终 call 指令
    str += str_call + str_arg + ")";
}


///
/// @brief 获取被调用函数的名字
/// @return std::string 被调用函数名字
///
std::string FuncCallInstruction::getCalledName() const
{
    return calledFunction->getName();
}
